package org.jaaksi.customviewdemo.view

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.toColorInt
import extension.dip
import extension.dp
import extension.sp
import org.jaaksi.customviewdemo.R
import kotlin.random.Random


// 先绘制实心Arc，然后再把内心圆擦掉
// todo 绘制指针动画，绘制呼吸动画
class BMIView2(context: Context?, attrs: AttributeSet?) :
    View(context, attrs) {

    val paint = Paint()
    val linePaint = Paint()
    val rectF = RectF()
    val textRectF = RectF()
    var textMeasureRect: Rect = Rect()
    val rectInset = RectF()

    //    val strokeWith = 50 * 2f
    val colors = arrayListOf(
        "#436DFF".toColorInt(),
        "#2294EA".toColorInt(),
        "#53AEF5".toColorInt(),
        "#A8C526".toColorInt(),
        "#FECD2E".toColorInt(),
        "#FD9845".toColorInt(),
        "#F67D3C".toColorInt(),
    )

    val values = arrayOf(
        16f,
        17f,
        18.5f,
        25.8f,
        30f,
        35.1f,
        40f,
    )

    var startAngle: Float = 180.0f
    var center = 0f

    // 内圆半径
    var insideRadius = 70f.dp

    // 圆弧宽度
    var ringWidth = 60f.dp

    // 不能小于指针图片的 宽度/2（指针底部是个半圆），否则旋转的时候，指针可能展示不完全
    var bottomOffset = 13.dp

    // RectF
//    var rectFRadius = 0f
    val sweepAngle = 180f / colors.size
    var textSpace = 5.dp

    val path = Path()
    val xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

    val bMatrix = Matrix()
    val bitmap: Bitmap =
        resources.getDrawable(R.drawable.icon_bmi_pointer)
            .toBitmap((22 * 1.1).dip, (90 * 1.1).dip)
    private var anim: ValueAnimator? = null
    private var currAngle: Float = 0f

    init {
        //禁用硬件加速，某些API不支持硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        paint.apply {
            style = Paint.Style.FILL
            isAntiAlias = true
            textSize = 14.sp
            textAlign = Paint.Align.CENTER
            typeface = ResourcesCompat.getFont(getContext(), R.font.barlow_regular)
        }

        linePaint.apply {
            style = Paint.Style.STROKE
            strokeWidth = 1f
            isAntiAlias = true
            color = Color.RED
        }
        post {
            startAnim(Random.nextDouble(1.0, 180.0).toFloat())
        }

    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        paint.getTextBounds("1234567890", 0, 10, textMeasureRect)
        val tWith: Int
        val tHeight: Int
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
            tWith =
                (ringWidth + insideRadius + textMeasureRect.height() + textSpace + 0.5).toInt() * 2
            tHeight =
                (ringWidth + insideRadius + bottomOffset + textMeasureRect.height() + textSpace + 0.5).toInt()
        } else {
            tWith = MeasureSpec.getSize(widthMeasureSpec)
            ringWidth =
                (tWith / 2f - insideRadius - textMeasureRect.height() - textSpace).toInt()
                    .toFloat() // 避免越界
            tHeight = (tWith / 2f + bottomOffset + 0.5).toInt()
        }

        setMeasuredDimension(tWith, tHeight)
    }


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        center = w / 2f
        val rectFRadius = ringWidth + insideRadius
        rectF.set(
            center - rectFRadius,
            center - rectFRadius,
            center + rectFRadius,
            center + rectFRadius,
        )
        textRectF.set(
            rectF.left - textSpace,
            rectF.top - textSpace,
            rectF.right + textSpace,
            rectF.bottom + textSpace
        )
        rectInset.set(
            center - insideRadius,
            center - insideRadius,
            center + insideRadius,
            center + insideRadius,
        )
    }

    override fun onDraw(canvas: Canvas) {
        // 使用离屏绘制。这里要新建一个图层
        paint.xfermode = null
        // resume的时候会重绘，这里要重置数据
        startAngle = 180f
        // 这里新建一个图层，避免把背景色给擦掉
        val layerID = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), paint)
        colors.forEachIndexed { index, color ->
            paint.color = color
            // userCenter控制是否绘制弧形起止位置与中心点的连线，角度坐标系x轴右边是0,顺时针
            canvas.drawArc(
                rectF,
                startAngle,
                sweepAngle,
                true,
                paint
            )
            val text = values[index].toString()
            startAngle += sweepAngle
            if (index != colors.lastIndex) {
                paint.color = Color.BLACK
                paint.getTextBounds(
                    text,
                    0,
                    text.length,
                    textMeasureRect
                )
                path.reset()
                // 弧长公式L=θ * π * r/180 θ = L * 180 / r / π
                val angle =
                    (textMeasureRect.width() * 180f / Math.PI / (ringWidth + insideRadius + textSpace)).toFloat()
                path.addArc(textRectF, startAngle - angle / 2f, angle)
                canvas.drawPath(path, linePaint)
                canvas.drawTextOnPath(text, path, 0f, 0f, paint)
            }
        }

        paint.xfermode = xfermode
        canvas.drawArc(rectInset, 180f, 180f, true, paint)
        paint.xfermode = null
        linePaint.color = Color.RED
        canvas.drawRect(rectF, linePaint)
        canvas.drawLine(center, 0f, center, height.toFloat(), linePaint)
        canvas.restoreToCount(layerID)

        // 绘制指针
        drawPoint(canvas, currAngle)
    }

    private fun drawPoint(canvas: Canvas, angle: Float) {
        bMatrix.reset()
        // 先旋转再平移。旋转中心为
        bMatrix.postRotate(angle - 90f, bitmap.width / 2f, bitmap.height - bottomOffset)
        bMatrix.postTranslate(center - bitmap.width / 2f, (height - bitmap.height).toFloat())
        canvas.drawBitmap(bitmap, bMatrix, paint)
    }

    private fun startAnim(angle: Float) {
        anim?.cancel()
        anim = ValueAnimator.ofFloat(0f, angle).apply {
            duration = 1000
            addUpdateListener {
                currAngle = it.animatedValue as Float
                postInvalidate()
            }
            start()
        }

    }

}